/* BASE RULE  XXX DOES NOT USE BUILT-IN DETECTION FUNCTION XXX
 alert tcp $EXTERNAL_NET $HTTP_PORTS -> $HOME_NET any (msg:"WEB-CLIENT Adobe Reader JP2C Region Atom CompNum memory corruption attempt"; flow:to_client,established; flowbits:isset,file.pdf; content:"jP|20 20|"; content:"|FF 4F FF 51|"; distance:0; metadata:policy balanced-ips drop, policy security-ips drop, service http; reference:cve,2009-3955; classtype:attempted-user; sid:16370;)
*/
/*
 * Use at your own risk.
 *
 * Copyright (C) 2005-2008 Sourcefire, Inc.
 * 
 * This file is autogenerated via rules2c, by Brian Caswell <bmc@sourcefire.com>
 */


#include "sf_snort_plugin_api.h"
#include "sf_snort_packet.h"

#include "so-util.h"

/* declare detection functions */
int rule16370eval(void *p);

/* declare rule data structures */
/* flow:established, to_client; */
static FlowFlags rule16370flow0 = 
{
    FLOW_ESTABLISHED|FLOW_TO_CLIENT
};

static RuleOption rule16370option0 =
{
    OPTION_TYPE_FLOWFLAGS,
    {
        &rule16370flow0
    }
};
/* flowbits:isset "file.pdf"; */
static FlowBitsInfo rule16370flowbits1 =
{
    "file.pdf",
    FLOWBIT_ISSET,
    0,
};

static RuleOption rule16370option1 =
{
    OPTION_TYPE_FLOWBIT,
    {
        &rule16370flowbits1
    }
};
#ifndef CONTENT_FAST_PATTERN
#define CONTENT_FAST_PATTERN 0
#endif
// content:"jP  ", depth 0, fast_pattern; 
static ContentInfo rule16370content2 = 
{
    (uint8_t *) "jP  ", /* pattern (now in snort content format) */
    0, /* depth */
    0, /* offset */
    CONTENT_FAST_PATTERN|CONTENT_BUF_NORMALIZED, /* flags */
    NULL, /* holder for boyer/moore PTR */
    NULL, /* more holder info - byteform */
    0, /* byteform length */
    0 /* increment length*/
};

static RuleOption rule16370option2 = 
{
    OPTION_TYPE_CONTENT,
    {
        &rule16370content2
    }
};
// content:"|FF|O|FF|Q", depth 0; 
static ContentInfo rule16370content3 = 
{
    (uint8_t *) "|FF|O|FF|Q", /* pattern (now in snort content format) */
    0, /* depth */
    0, /* offset */
    CONTENT_BUF_NORMALIZED|CONTENT_RELATIVE, /* flags */
    NULL, /* holder for boyer/moore PTR */
    NULL, /* more holder info - byteform */
    0, /* byteform length */
    0 /* increment length*/
};

static RuleOption rule16370option3 = 
{
    OPTION_TYPE_CONTENT,
    {
        &rule16370content3
    }
};

/* references for sid 16370 */
/* reference: cve "2009-3955"; */
static RuleReference rule16370ref1 = 
{
    "cve", /* type */
    "2009-3955" /* value */
};

static RuleReference *rule16370refs[] =
{
    &rule16370ref1,
    NULL
};
/* metadata for sid 16370 */
/* metadata:service http, policy balanced-ips drop, policy security-ips drop; */
static RuleMetaData rule16370service1 = 
{
    "service http"
};


//static RuleMetaData rule16370policy1 = 
//{
//    "policy balanced-ips drop"
//};
//
//static RuleMetaData rule16370policy2 = 
//{
//    "policy security-ips drop"
//};

static RuleMetaData rule16370policy3 = 
{
    "policy max-detect-ips drop"
};


static RuleMetaData *rule16370metadata[] =
{
    &rule16370service1,
//    &rule16370policy1,
//    &rule16370policy2,
    &rule16370policy3,
    NULL
};

RuleOption *rule16370options[] =
{
    &rule16370option0,
    &rule16370option1,
    &rule16370option2,
    &rule16370option3,
    NULL
};

Rule rule16370 = {
   /* rule header, akin to => tcp any any -> any any */
   {
       IPPROTO_TCP, /* proto */
       "$EXTERNAL_NET", /* SRCIP     */
       "$HTTP_PORTS", /* SRCPORT   */
   
       0, /* DIRECTION */
       "$HOME_NET", /* DSTIP     */
   
       "any", /* DSTPORT   */
   },
   /* metadata */
   { 
       3,  /* genid */
       16370, /* sigid */
       7, /* revision */
       "attempted-user", /* classification */
       0,  /* hardcoded priority XXX NOT PROVIDED BY GRAMMAR YET! */
       "FILE-PDF Adobe Reader JP2C Region Atom CompNum memory corruption attempt",     /* message */
       rule16370refs /* ptr to references */
       ,rule16370metadata
   },
   rule16370options, /* ptr to rule options */
   &rule16370eval, /* use the built in detection function */
   0 /* am I initialized yet? */
};


/* detection functions */
int rule16370eval(void *p) {
    const uint8_t *cursor_normal = 0;
    SFSnortPacket *sp = (SFSnortPacket *) p;

    const uint8_t *beg_of_payload, *end_of_payload;
    uint16_t Csiz;
    uint16_t atomlen;
    uint16_t Crgn;

    if(sp == NULL)
        return RULE_NOMATCH;

    if(sp->payload == NULL)
        return RULE_NOMATCH;
    
    // flow:established, to_client;
    if (checkFlow(p, rule16370options[0]->option_u.flowFlags) > 0 ) {
        // flowbits:isset "file.pdf";
        if (processFlowbits(p, rule16370options[1]->option_u.flowBit) > 0) {
                // content:"jP  ", depth 0, fast_pattern;
            if (contentMatch(p, rule16370options[2]->option_u.content, &cursor_normal) > 0) {
                // content:"|FF|O|FF|Q", depth 0;
                if (contentMatch(p, rule16370options[3]->option_u.content, &cursor_normal) > 0) {

                    if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_payload, &end_of_payload) <= 0)
                        return RULE_NOMATCH;

                    //Make sure at least the entire atom is present, as well as
                    //the atom signature and length of the following atom
                    if(cursor_normal + 47 + 4 > end_of_payload)
                        return RULE_NOMATCH;

                    // Now make sure this atomlen is 47
                    if(*cursor_normal != 0 || *(cursor_normal + 1) != 47)
                       return RULE_NOMATCH;

                    //Extract the value of Csiz
                    Csiz = read_big_16(cursor_normal + 36);

                    //Jump to the next atom, just before the signature
                    cursor_normal += 47; //atomlen;

                    //Check to see if the following byte is FF (eg:the first byte of a signature)
                    //and that we haven't ended up in no man's land
                    while((cursor_normal + 4 < end_of_payload) && (*cursor_normal == 255)) {
                  
                        //Extract the length of next atom
                        atomlen = read_big_16(cursor_normal+2);

                        //Make sure the whole atom is present. Atom length is atomlen + file signature (2 bytes)
                        if ((cursor_normal + atomlen + 2) > end_of_payload)
                            return RULE_NOMATCH;

                        //Check second byte of atom signature
                        //A FF5E is the Region-of-interest atom
                         if (*(cursor_normal+1) == '\x5e') {
                            
                            //This atom can only be either 5 or 6 bytes long, but no other value.
                            //Crgn will be either 1 or 2 bytes depending on this length.
                            //Exit if you some unexpected value.
                            if (atomlen == 5)
                                Crgn = *(cursor_normal+4);
                            else if (atomlen == 6) {
                                Crgn = read_big_16(cursor_normal+4);
                            }
                            else
                                return RULE_NOMATCH;

                            //Fire if Crgn >= Csiz
                            if (Crgn >= Csiz)
                                return RULE_MATCH;
                        }

                        //Skip to next atom
                        cursor_normal += atomlen + 2;

                    }
                }
            }
        }
    }
    return RULE_NOMATCH;
}

/*
Rule *rules[] = {
    &rule16370,
    NULL
};
*/

